package org.smartercontext.contextmger.providers;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;

import org.smartercontext.contextmger.contextsphere.ContextManagerController;
import org.smartercontext.contextmger.contextsphere.ContextSphereController;
import org.smartercontext.contextmger.contextsphere.Permissions;
import org.smartercontext.contextmger.converters.Formatter;

import com.hp.hpl.jena.ontology.DatatypeProperty;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.sun.xml.ws.api.security.trust.STSTokenProvider;


public class Provider implements IProvider {

	@Override
	public String provideContext(String username, String typeInf, String format) {
		
		try {
			
			ContextManagerController.contextManagerController();
			Model usermodel=ContextManagerController.getUsermodel(username);
			
			ContextSphereController csc = new ContextSphereController();
			List<Permissions>perms = csc.listPermissionsByUser(username);
			List<Permissions>totalP = csc.listPermissions();
			
			Model usermodelPerms = ModelFactory.createDefaultModel();
			usermodelPerms.setNsPrefixes(ContextManagerController.getMappings());
			
			String nsUser="http://smartercontext.org/vocabularies/rdf/"+username+".rdf#";
			Resource resource = usermodel.getResource(nsUser+username);
			Property rdfType = usermodelPerms.createProperty(ContextManagerController.getRdf(),"type");
			Property userEmali = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(), "emailAccount");
			Property nameUseri = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(), "givenName");
			
			OntModel model = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM_MICRO_RULE_INF);;
			model.setNsPrefixes(ContextManagerController.getMappings());
			DatatypeProperty hasMobile = model.createDatatypeProperty(ContextManagerController.getNsSchemaGC()+"hasMobile");
			Property genderP = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasGender");
			Property birthdayP = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"birthYear");
			Property relStatusP = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"relationShipStatus");
			Property engagedTo = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"engagedTo");
			Property locatedIn = usermodelPerms.createProperty(ContextManagerController.getNsSchemaGC(),"locatedIn");
			Property preferredLocation = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(), "preferredLocation");
			Property studiedAt = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"studiedAt");
			Property studiesAt = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"studiesAt"); 
			Property workedAt = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"workedAt");
			Property worksAt = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"worksAt");
			Property friendOf = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"friendOf");
			Property hasAsAunt = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsAunt");
			Property hasAsBrotherInLaw = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsBrotherInLaw");
			Property hasAsBrother = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsBrother");
			Property hasAsCousin = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsCousin");
			Property hasAsDaugtherInLaw = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsDaugtherInLaw");
			Property parentOf = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"parentOf");
			Property hasAsFamilyMember = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsFamilyMember");
			Property childOf = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"childOf");
			Property hasAsFatherInLaw = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsFatherInLaw");
			Property hasAsGrandChild = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsGrandChild");
			Property hasAsGrandMa = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsGrandMa");
			Property hasAsGrandPa = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsGrandPa");
			Property hasAsHalfBro = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsHalfBro");
			Property hasAsHalfSister = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsHalfSister");
			Property hasAsMotherInLaw = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsMotherInLaw");
			Property hasAsNephew = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsNephew");
			Property hasAsNiece = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsNiece");
			Property hasAsSister = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsSister");
			Property hasAsSisterInLaw = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsSisterInLaw");
			Property hasAsSonInLaw = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsSonInLaw");
			Property hasAsStepBrother = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsStepBrother");
			Property hasAsStepDaugther = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsStepDaugther");
			Property hasAsStepFather = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsStepFather");
			Property hasAsStepMother = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsStepMother");
			Property hasAsStepSister = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsStepSister");
			Property hasAsStepSon = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsStepSon");
			Property hasAsUncle = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL(),"hasAsUncle");
			Property prefpayMMT = usermodelPerms.createProperty(ContextManagerController.getNsSchemaShopping()+"preferredUserPaymentMethod");
			Property payMMT = usermodelPerms.createProperty(ContextManagerController.getNsSchemaShopping()+"paymentMethodType");
			Property wishesP = usermodelPerms.createProperty(ContextManagerController.getNsSchemaShopping(),"wishes");
			Property rankedP = usermodelPerms.createProperty(ContextManagerController.getNsSchemaShopping(),"ranked");
			Property likes = usermodelPerms.createProperty(ContextManagerController.getNsSchemaPERSONAL()+"likes");
			
			if(perms.size()>0){
				
				if(perms.size()==totalP.size()){
					
					usermodelPerms = usermodel;
					
				}else{
					
					for(int i=0;i<perms.size();i++){
						Permissions permmission = perms.get(i);
						int idPerm = permmission.getIdPermission().intValue();
						
						switch (idPerm) {
						case 1:
							
							usermodelPerms.add(resource.getProperty(rdfType));
							usermodelPerms.add(resource.listProperties(userEmali));
							usermodelPerms.add(resource.getProperty(nameUseri));
							usermodelPerms.add(resource.listProperties(hasMobile));
							
							StmtIterator it = resource.listProperties(hasMobile);
							while(it.hasNext()){
								Statement stmt = it.next();
								String object = stmt.getObject().toString();
								Resource temp = usermodel.getResource(object);
								StmtIterator it2 = temp.listProperties();
								usermodelPerms.add(it2);
							}
							
							usermodelPerms.add(resource.listProperties(genderP));
							usermodelPerms.add(resource.listProperties(birthdayP));
							usermodelPerms.add(resource.listProperties(relStatusP));
							
							if(resource.hasProperty(engagedTo)){
								Statement stmt = resource.getProperty(engagedTo);
								usermodelPerms.add(stmt);
								Resource person = usermodel.getResource(stmt.getObject().toString());
								usermodelPerms.add(person.listProperties());
							}
							
							break;

						case 2:
														
							if(resource.hasProperty(preferredLocation)){
								Statement stmt = resource.getProperty(preferredLocation);
								usermodelPerms.add(stmt);
								Resource resS = usermodel.getResource(stmt.getObject().toString());
								usermodelPerms.add(getCompleteLocation(usermodel, resS, locatedIn));
							}
							
							break;
						case 3:
							
							StmtIterator itStudiedAt = resource.listProperties(studiedAt);
							while(itStudiedAt.hasNext()){
								Statement stmt = itStudiedAt.next();
								usermodelPerms.add(stmt);
								Resource resS = usermodel.getResource(stmt.getObject().toString());
								usermodelPerms.add(getCompleteLocation(usermodel, resS, locatedIn));
								
							}
							
							StmtIterator itStudiesAt = resource.listProperties(studiesAt);
							while(itStudiesAt.hasNext()){
								Statement stmt = itStudiesAt.next();
								usermodelPerms.add(stmt);
								Resource resS = usermodel.getResource(stmt.getObject().toString());
								usermodelPerms.add(getCompleteLocation(usermodel, resS, locatedIn));
							}
							
							StmtIterator itWorkedAt = resource.listProperties(workedAt);
							while(itWorkedAt.hasNext()){
								Statement stmt = itWorkedAt.next();
								usermodelPerms.add(stmt);
								Resource resS = usermodel.getResource(stmt.getObject().toString());
								usermodelPerms.add(getCompleteLocation(usermodel, resS, locatedIn));
								
							}
							
							StmtIterator itWorksAt = resource.listProperties(worksAt);
							while(itWorksAt.hasNext()){
								Statement stmt = itWorksAt.next();
								usermodelPerms.add(stmt);
								Resource resS = usermodel.getResource(stmt.getObject().toString());
								usermodelPerms.add(getCompleteLocation(usermodelPerms, resS, locatedIn));
							}
							
							break;
						case 4:
							
							usermodelPerms.add(getFandF(usermodel, resource, hasAsUncle));
							usermodelPerms.add(getFandF(usermodel, resource, friendOf ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsAunt ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsBrotherInLaw ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsBrother ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsCousin ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsDaugtherInLaw ));
							usermodelPerms.add(getFandF(usermodel, resource, parentOf ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsFamilyMember ));
							usermodelPerms.add(getFandF(usermodel, resource, childOf ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsFatherInLaw ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsGrandChild ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsGrandMa ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsGrandPa ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsHalfBro ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsHalfSister ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsMotherInLaw ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsNephew ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsNiece ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsSister ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsSisterInLaw ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsSonInLaw ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsStepBrother ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsStepDaugther ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsStepFather ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsStepMother ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsStepSister ));
							usermodelPerms.add(getFandF(usermodel, resource, hasAsStepSon  ));
							
							break;
						case 5:
							
							if(resource.hasProperty(prefpayMMT)){
								Statement stmt = resource.getProperty(prefpayMMT);
								usermodelPerms.add(stmt);
								
								Resource resS = usermodel.getResource(stmt.getObject().toString());
								usermodelPerms.add(resS.listProperties());
								
								if(resS.hasProperty(payMMT)){
									Statement stmt2 = resS.getProperty(payMMT);
									Resource res2 = usermodel.getResource(stmt2.getObject().toString());
									usermodelPerms.add(res2.listProperties());
								}
							}
							
							break;
						case 6:
							
							StmtIterator itWishes = resource.listProperties(wishesP);
							
							while(itWishes.hasNext()){
								Statement stmt = itWishes.next();
								Resource res = usermodel.getResource(stmt.getObject().toString());
								usermodelPerms.add(res.listProperties());
							}
							usermodelPerms.add(resource.listProperties(wishesP));
							
							StmtIterator itRanked = resource.listProperties(rankedP);
							
							while(itRanked.hasNext()){
								Statement stmt = itRanked.next();
								Resource res = usermodel.getResource(stmt.getObject().toString());
								usermodelPerms.add(res.listProperties());
							}
							usermodelPerms.add(resource.listProperties(rankedP));
							break;
						case 7:
							
							StmtIterator itLikes = resource.listProperties(likes);
							
							while(itLikes.hasNext()){
								Statement stmt = itLikes.next();
								Resource res = usermodel.getResource(stmt.getObject().toString());
								usermodelPerms.add(res.listProperties());
							}
							usermodelPerms.add(resource.listProperties(likes));
							
							break;
						case 8:
							
							if(resource.hasProperty(locatedIn)){
								Statement stmt = resource.getProperty(locatedIn);
								usermodelPerms.add(stmt);
								Resource resS = usermodel.getResource(stmt.getObject().toString());
								usermodelPerms.add(getCompleteLocation(usermodel, resS, locatedIn));
								
							}
							
							break;
						}
					}
					
				}
				
			}else{
				return "The user has not granted any permissions";
			}
			
			if(usermodelPerms!=null){
				if(typeInf.equals("all")){
					if(format.equals("json")){
						Formatter formater = new Formatter();
						return formater.applyFormat(usermodelPerms, format, username);
						
					}else if(format.equals("rdfxml")){
						//Revisar que se puede quitar
						File modelFileProv = File.createTempFile("rdftempprov", "rdf");
						FileOutputStream fout = new FileOutputStream(modelFileProv);
						usermodelPerms.write(fout);
						
						BufferedReader reader = new BufferedReader(new FileReader(modelFileProv));
						String line;
						
						String text="";
						while((line=reader.readLine())!=null){
							text+="\n"+line;
						}
						
						return text;
					}else{
						//For future developments (e.g: RDFN3, TURTLERDF, XML)
					}
				}else{
					//For future developments (Build an API for SmarterContext)
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		
		return null;
	}

	public List<Statement> getCompleteLocation(Model usermodel, Resource resource, Property prop){
		
		List<Statement>list = new ArrayList<>();
		
		list.addAll(resource.listProperties().toList());
		if(resource.hasProperty(prop)){
			Statement stmt = resource.getProperty(prop);
			Resource temp = usermodel.getResource(stmt.getObject().toString());
			list.addAll(getCompleteLocation(usermodel, temp, prop));
		
	}
		
		return list;
	}
	
	public List<Statement> getFandF(Model usermodel,Resource resource, Property prop){
		
		List<Statement>list = new ArrayList<>();
		
		StmtIterator iterator = resource.listProperties(prop);
		list.addAll(resource.listProperties(prop).toList());
		while(iterator.hasNext()){
			Statement stmt = iterator.next();
			Resource person = usermodel.getResource(stmt.getObject().toString());
			list.addAll(person.listProperties().toList());
		}
		
		return list;
		
	}

}
